﻿#region Copyright and License Notice
// Copyright (C)2010-2016 - Rob Levine and other contributors
// http://configgen.codeplex.com
// 
// This file is part of ConfigGen.
// 
// ConfigGen is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// ConfigGen is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License and 
// the GNU Lesser General Public License along with ConfigGen.  
// If not, see <http://www.gnu.org/licenses/>
#endregion

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConfigGen.Utilities.Extensions.System.Collections.Generic
{
    /// <summary>
    /// Extension methods for Dictionary class
    /// </summary>
    public static class DictionaryExtensions
    {
        /// <summary>
        /// Returns a merged "count" dictionary from the current dictionary merged with the supplied dictionary. 
        /// A "count" dictionary is one with a string key, and an integer value which acts as a counter for the key.
        /// </summary>
        /// <remarks>
        /// <para>By way of illustration, if dictionary one contains: {"item1", 2"} and {"item2", 2} and dictionary 2 contains {"item2", 2"} and {"item3", 2},
        /// then the merged count dictionary would contain:  {"item1", 2"}, {"item2", 4} and {"item3", 2}.</para>
        /// </remarks>
        /// <param name="dictionary1">Count dictionary 1</param>
        /// <param name="dictionary2">Count dictionary 2</param>
        /// <returns>Count dictionary created by merging the two supplied dictionary.</returns>
        /// <exception cref="ArgumentNullException">Raised if either dictionary is null.</exception>
        public static IDictionary<string, int> GetMergedCountDictionary(this IDictionary<string, int> dictionary1, IDictionary<string, int> dictionary2)
        {
            if (dictionary1 == null) throw new ArgumentNullException("dictionary1");
            if (dictionary2 == null) throw new ArgumentNullException("dictionary2");

            var mergedDictionary = new Dictionary<string, int>(dictionary1);
            foreach (var key in dictionary2.Keys)
            {
                if (mergedDictionary.ContainsKey(key))
                {
                    mergedDictionary[key] += dictionary2[key];
                }
                else
                {
                    mergedDictionary.Add(key, 1);
                }
            }
            return mergedDictionary;
        }

        /// <summary>
        /// Adds the supplied list of keys to the current "count" dictionary, with a count of zero, and returns the updated dictionary.  
        /// A "count" dictionary is one with a string key, and an integer value which acts as a counter for the key.
        /// </summary>
        /// <param name="dictionary">"Count" dictionary</param>
        /// <param name="keys">List of keys to add</param>
        /// <returns>The updated count dictionary.</returns>
        /// <exception cref="ArgumentNullException">Raised if either arument is null.</exception>
        public static IDictionary<string, int> AddKeysToCountDictionary(this IDictionary<string, int> dictionary, IEnumerable<string> keys)
        {
            if (dictionary == null) throw new ArgumentNullException("dictionary");
            if (keys == null) throw new ArgumentNullException("keys");

            foreach (var key in keys.Where(key => !dictionary.ContainsKey(key)))
            {
                dictionary.Add(key, 0);
            }

            return dictionary; 
        }

        /// <summary>
        /// Increments the count for the specified key if it is already present in the "count" dictionary, otherwise adds the key with
        /// a count of one. A "count" dictionary is one with a string key, and an integer value which acts as a counter for the key.
        /// </summary>
        /// <param name="dictionary">"Count" dictionary</param>
        /// <param name="key">Ket to increment</param>
        /// <exception cref="ArgumentNullException">Raised if either arument is null.</exception>
        /// <exception cref="ArgumentException">Raised if <paramref name="key"/> arument is zero length.</exception>
        public static void IncrementCountForKey(this IDictionary<string, int> dictionary, string key)
        {
            if (dictionary == null) throw new ArgumentNullException("dictionary");
            if (key == null) throw new ArgumentNullException("key");
            if (key.Length == 0) throw new ArgumentException("key");

            if (dictionary.ContainsKey(key))
            {
                dictionary[key]++;
            }
            else
            {
                dictionary.Add(key, 1);
            }
        }
    }
}
